﻿using P002_SudukuSolver_Mvvm.ViewModels;
using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace P002_SudukuSolver_Mvvm.Commands;


public class SolveCommand : ICommand
{
    private MainWindowViewModel Main { get; } = MainWindowViewModel.Instance;

    public event EventHandler? CanExecuteChanged;

    public bool CanExecute(object? parameter)
    {
        return MainWindowViewModel.Instance.SudukuViewModel != null;
    }

    public void Execute(object? parameter)
    {
        if (Main != null || Main.SudukuViewModel != null)
        {
            switch (Main.SolveState)
            {
                case SolveState.Solving:
                    // 如果是在计算中，那就暂停
                    Main.SolveReset.Reset();
                    Main.SolveState = SolveState.Pause;
                    return;
                case SolveState.Stop:
                    //如果没有开始，那就开始，并将状态设置为计算中
                    Main.SolveState = SolveState.Solving;

                    Main.SolveCancel = new CancellationTokenSource(); // 已经取消的任务，要想重新开始需要新建一个cts
                    Main.SolveReset = new ManualResetEvent(true);
                    Main.SolveTask = new Task(() => Start(), Main.SolveCancel.Token);
                    Main.SolveTask.Start();
                    break;
                case SolveState.Pause:
                    // 如果使暂停，那就继续计算
                    Main.SolveState = SolveState.Solving;
                    Main.SolveReset.Set();
                    break;
                default:
                    break;
            }
        }
    }

    private void Start()
    {
        Application.Current.Dispatcher.Invoke(() => Main.SudukuViewModel.Resume()); // 开始前将数独重置为初始状态
        SolveResult result = Solve(Main.SudukuViewModel.Suduku, 0, 0);
    }

    private SolveResult Solve(BindingList<BindingList<CellViewModel>> suduku, int bigNine, int nine)
    {
        if (Main.SolveCancel.IsCancellationRequested)
        {
            return SolveResult.Cancel;
        }
        Main.SolveReset.WaitOne();

        var cell = suduku[bigNine][nine];
        if (!cell.IsEnabled)
        {
            // 如果当前格子不需要计算，就进行下一个；
            // 至于下一个是哪个格子，将会在Next中计算出来
            return Next(suduku, bigNine, nine);
        }
        else
        {
            // 如果当前格子需要计算，就一个一个测试
            cell.UpdateCases();
            while (cell.Next())
            {
                Thread.Sleep(500);
                // 因为更新过这个格子的所有可能性了，所以，只要进入while循环就说明这个格子还有可以填的数

                // 只有失败了才继续下一个，否则直接返回状态
                var result = Next(suduku, bigNine, nine);
                if (result == SolveResult.Failure)
                {
                    continue;
                }
                else
                {
                    return result;
                }
            }
            return SolveResult.Failure; // 这个格子所有的可能性都测试完了就是返回false
        }
    }

    private SolveResult Next(BindingList<BindingList<CellViewModel>> suduku, int bigNine, int nine)
    {
        // 如果当前大九宫都计算完了，那就下一个大九宫
        // 如果所有的大九宫都计算完了，那就返回true
        if (nine < 8)
        {
            nine++;
        }
        else
        {
            if (bigNine < 8)
            {
                bigNine++;
                nine = 0;
            }
            else
            {
                MainWindowViewModel.Instance.SolveState = SolveState.Stop;
                return SolveResult.Success;
            }
        }

        return Solve(suduku, bigNine, nine);
    }
}
